package org.zetaframework.satoken;

import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.spring.pathmatch.SaPatternsRequestConditionHolder;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.strategy.SaStrategy;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.zetaframework.core.properties.DatabaseProperties;
import org.zetaframework.core.properties.IgnoreProperties;
import org.zetaframework.core.properties.TokenProperties;
import org.zetaframework.core.utils.ContextUtil;
import org.zetaframework.satoken.interceptor.ClearThreadLocalInterceptor;
import org.zetaframework.satoken.interceptor.SameTokenInterceptor;
import org.zetaframework.satoken.interceptor.TraceInterceptor;


/**
 * Sa-Token 权限认证 配置类
 * @author gcc
 */
@Configuration
@EnableConfigurationProperties({IgnoreProperties.class, TokenProperties.class})
public class SaTokenConfigure implements WebMvcConfigurer {

    private final DatabaseProperties dataBaseProperties;
    private final IgnoreProperties ignoreProperties;
    public SaTokenConfigure(DatabaseProperties dataBaseProperties, IgnoreProperties ignoreProperties) {
        this.dataBaseProperties = dataBaseProperties;
        this.ignoreProperties = ignoreProperties;
    }

    static {
        // 重写路由匹配算法，切换为 ant_path_matcher 模式，使之可以支持 `**` 之后再出现内容
        SaStrategy.instance.routeMatcher = SaPatternsRequestConditionHolder::match;
    }

    /**
     * <p>拦截器配置</p>
     *
     * 说明：
     * <pre>
     * 可以在这里使用<a href="https://sa-token.cc/doc.html#/use/route-check">拦截器鉴权</a>
     * 针对某个接口，某些接口单独进行权限校验
     * </pre>
     * @param registry InterceptorRegistry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // SameToken拦截器
        registry.addInterceptor(new SameTokenInterceptor()).addPathPatterns("/**").excludePathPatterns("/error");
        // 链路追踪拦截器
        registry.addInterceptor(new TraceInterceptor()).addPathPatterns("/**").excludePathPatterns("/error");
        // 登录认证拦截器
        registry.addInterceptor(new SaInterceptor(auth ->{
            if (!StpUtil.isLogin()) { return; }

            // 获取用户id，并设置到ThreadLocal中。（mybatis-plus自动填充用到）
            switch (dataBaseProperties.getUserIdType()) {
                case Long -> ContextUtil.setUserId(StpUtil.getLoginIdAsLong());
                case Int -> ContextUtil.setUserId(StpUtil.getLoginIdAsInt());
                case String -> ContextUtil.setUserId(StpUtil.getLoginIdAsString());
                default -> {
                }
            }
            ContextUtil.setToken(StpUtil.getTokenValue());
        })).addPathPatterns("/**").excludePathPatterns(ignoreProperties.getNotMatchUrl());
        // 清空ThreadLocal数据拦截器
        registry.addInterceptor(new ClearThreadLocalInterceptor()).addPathPatterns("/**").excludePathPatterns("/error");
    }

}
